﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace 桌面视频录制
{
    [Serializable]
    public class DrawRectangle : DrawObject
    {
        protected Point leftUpPoint;
        protected int width;
        protected int height;
        protected int selectedIndex;
        protected float angle = 0.0f;//弧度表示
        protected Point rightUpPoint;
        protected Point leftDownPoint;
        protected Point rightDownPoint;
        protected double slope;//矩形左侧边的斜率
        public DrawRectangle() { }
        public DrawRectangle(Point leftUpPoint)
        {
            this.leftUpPoint = leftUpPoint;
            this.rightUpPoint = new Point(leftUpPoint.X, leftUpPoint.Y);
            this.leftDownPoint = new Point(leftUpPoint.X, leftUpPoint.Y);
            this.rightDownPoint = new Point(leftUpPoint.X, leftUpPoint.Y);
        }
        public override void Draw(Graphics g)
        {
            Pen pen = new Pen(this.PenColor);
            pen.Width = this.PenWidth;
            Matrix matrix = new Matrix();
            matrix.RotateAt((float)(angle * 180 / Math.PI), leftUpPoint);
            g.Transform = matrix;
            g.DrawRectangle(pen, leftUpPoint.X, leftUpPoint.Y, width, height);
            g.ResetTransform();
            matrix.Dispose();
            pen.Dispose();
        }
        public override void MouseMove(System.Windows.Forms.MouseEventArgs e)
        {
            int middleX = (leftUpPoint.X + rightDownPoint.X) / 2;
            int middleY = (leftUpPoint.Y + rightDownPoint.Y) / 2;
            if (e.X <= middleX && e.Y <= middleY)
            {
                this.leftUpPoint = new Point(e.X, e.Y);
                this.leftDownPoint.X = e.X;
                this.rightUpPoint.Y = e.Y;

                this.width = rightDownPoint.X - e.X;
                this.height = rightDownPoint.Y - e.Y;
            }
            else if (e.X >= middleX && e.Y <= middleY)
            {
                this.rightUpPoint = new Point(e.X, e.Y);
                this.leftUpPoint.Y = e.Y;
                this.rightDownPoint.X = e.X;

                this.width = e.X - leftDownPoint.X;
                this.height = leftDownPoint.Y - e.Y;
            }
            else if (e.X <= middleX && e.Y >= middleY)
            {
                this.leftDownPoint = new Point(e.X, e.Y);
                this.leftUpPoint.X = e.X;
                this.rightDownPoint.Y = e.Y;

                this.width = rightUpPoint.X - e.X;
                this.height = e.Y - rightUpPoint.Y;
            }
            else
            {
                this.rightDownPoint = new Point(e.X, e.Y);
                this.leftDownPoint.Y = e.Y;
                this.rightUpPoint.X = e.X;

                this.width = e.X - leftUpPoint.X;
                this.height = e.Y - leftUpPoint.Y;
            }
        }
        public override bool JudgeIsSelected(System.Windows.Forms.MouseEventArgs e)
        {
            GraphicsPath path = new GraphicsPath();
            path.AddPolygon(new Point[] { leftUpPoint, rightUpPoint, rightDownPoint, leftDownPoint });
            Region region = new Region(path);
            if (region.IsVisible(e.Location))
            {
                path.Dispose();
                region.Dispose();
                return true;
            }
            else
            {
                path.Dispose();
                region.Dispose();
                return false;
            }
        }
        protected PointF GetMiddlePoint(PointF p1, PointF p2)
        {
            float x = (p1.X + p2.X) / 2;
            float y = (p1.Y + p2.Y) / 2;
            return new PointF(x, y);
        }
        protected bool IsPointInRectangle(Point p1, Point p2, Point p3, Point p4, Point point)
        {
            return (IsPointAtLineLeft(p1, p2, point) && IsPointAtLineLeft(p2, p3, point) && !IsPointAtLineLeft(p3, p4, point) && !IsPointAtLineLeft(p4, p1, point));
        }
        private bool IsPointAtLineLeft(Point p1, Point p2, Point point)
        {
            if (p1.X > p2.X)
                return ((1.0 * (point.X - p1.X) / (p1.X - p2.X)) >= (1.0 * (point.Y - p1.Y) / (p1.Y - p2.Y)));
            else
                return !((1.0 * (point.X - p1.X) / (p1.X - p2.X)) >= (1.0 * (point.Y - p1.Y) / (p1.Y - p2.Y)));
        } 
        public override void DrawControlPoint(Graphics g)
        {
            StaticFunction.DrawControlRegion(g, leftUpPoint);
            StaticFunction.DrawControlRegion(g, rightUpPoint);
            StaticFunction.DrawControlRegion(g, new Point((leftUpPoint.X + rightUpPoint.X) / 2, (leftUpPoint.Y + rightUpPoint.Y) / 2));
            StaticFunction.DrawControlRegion(g, leftDownPoint);
            StaticFunction.DrawControlRegion(g, rightDownPoint);
            StaticFunction.DrawControlRegion(g, new Point((leftDownPoint.X + rightDownPoint.X) / 2, (leftDownPoint.Y + rightDownPoint.Y) / 2));
            StaticFunction.DrawControlRegion(g, new Point((leftUpPoint.X + leftDownPoint.X) / 2, (leftUpPoint.Y + leftDownPoint.Y) / 2));
            StaticFunction.DrawControlRegion(g, new Point((rightUpPoint.X + rightDownPoint.X) / 2, (rightUpPoint.Y + rightDownPoint.Y) / 2));

            Pen pen = new Pen(Color.Red);
            AdjustableArrowCap arrow = new AdjustableArrowCap(2, 2, true);
            pen.CustomEndCap = arrow;
            pen.CustomStartCap = arrow;
            g.DrawArc(pen, rightUpPoint.X - 7, rightUpPoint.Y - 7, 15, 15, -120, 180);
            pen.Dispose();
            pen = null;

        }
        public override void MoveLocation(MouseEventArgs e)
        {
            int dx = e.X - this.MouseDownPoint.X;
            int dy = e.Y - this.MouseDownPoint.Y;
            this.MouseDownPoint = new Point(e.X, e.Y);

            this.leftUpPoint = new Point(leftUpPoint.X + dx, leftUpPoint.Y + dy);
            rightUpPoint = new Point(rightUpPoint.X + dx, rightUpPoint.Y + dy);
            leftDownPoint = new Point(leftDownPoint.X + dx, leftDownPoint.Y + dy);
            rightDownPoint = new Point(rightDownPoint.X + dx, rightDownPoint.Y + dy);
        }
        public override bool JudgeIsInControlRegion(MouseEventArgs e)
        {
            Rectangle rect = StaticFunction.GetControlRect(leftUpPoint);
            if (rect.Contains(e.Location))
            {
                selectedIndex = 0;
                return true;
            }
            rect = StaticFunction.GetControlRect(leftDownPoint);
            if (rect.Contains(e.Location))
            {
                selectedIndex = 1;
                return true;
            }
            rect = StaticFunction.GetControlRect(rightUpPoint);
            if (rect.Contains(e.Location))
            {
                selectedIndex = 2;
                return true;
            }
            rect = StaticFunction.GetControlRect(rightDownPoint);
            if (rect.Contains(e.Location))
            {
                selectedIndex = 3;
                return true;
            }
            rect = StaticFunction.GetControlRect(new Point((leftUpPoint.X + rightUpPoint.X) / 2, (leftUpPoint.Y + rightUpPoint.Y) / 2));
            if (rect.Contains(e.Location))
            {
                selectedIndex = 4;
                return true;
            }
            rect = StaticFunction.GetControlRect(new Point((leftUpPoint.X + leftDownPoint.X) / 2, (leftUpPoint.Y + leftDownPoint.Y) / 2));
            if (rect.Contains(e.Location))
            {
                selectedIndex = 5;
                return true;
            }
            rect = StaticFunction.GetControlRect(new Point((leftDownPoint.X + rightDownPoint.X) / 2, (leftDownPoint.Y + rightDownPoint.Y) / 2));
            if (rect.Contains(e.Location))
            {
                selectedIndex = 6;
                return true;
            }
            rect = StaticFunction.GetControlRect(new Point((rightUpPoint.X + rightDownPoint.X) / 2, (rightUpPoint.Y + rightDownPoint.Y) / 2));
            if (rect.Contains(e.Location))// || rect2.Contains(e.Location))
            {
                selectedIndex = 7;
                return true;
            }
            return false;
        }
        public override void ChangeSize(MouseEventArgs e)
        {
            if (selectedIndex == 0)
            {
                if (leftUpPoint.X != leftDownPoint.X)
                {
                    leftDownPoint = GetChangeSizePoint(slope, rightDownPoint, e);
                    rightUpPoint = GetChangeSizePoint(-1 / slope, rightDownPoint, e);
                }
                else
                {
                    leftDownPoint.X = e.X;
                    rightUpPoint.Y = e.Y;
                }
                leftUpPoint = new Point(e.X, e.Y);
                width = (int)(Math.Sqrt(Math.Pow(rightUpPoint.X - leftUpPoint.X, 2) + Math.Pow(rightUpPoint.Y - leftUpPoint.Y, 2)));
                height = (int)(Math.Sqrt(Math.Pow(leftUpPoint.X - leftDownPoint.X, 2) + Math.Pow(leftUpPoint.Y - leftDownPoint.Y, 2)));
            }
            else if (selectedIndex == 1)
            {
                if (leftUpPoint.X != leftDownPoint.X)
                {
                    leftUpPoint = GetChangeSizePoint(slope, rightUpPoint, e);
                    rightDownPoint = GetChangeSizePoint(-1 / slope, rightUpPoint, e);

                }
                else
                {
                    leftUpPoint.X = e.X;
                    rightDownPoint.Y = e.Y;
                }
                leftDownPoint = new Point(e.X, e.Y);
                width = (int)(Math.Sqrt(Math.Pow(rightUpPoint.X - leftUpPoint.X, 2) + Math.Pow(rightUpPoint.Y - leftUpPoint.Y, 2)));
                height = (int)(Math.Sqrt(Math.Pow(leftUpPoint.X - leftDownPoint.X, 2) + Math.Pow(leftUpPoint.Y - leftDownPoint.Y, 2)));
            }
            else if (selectedIndex == 2)
            {
                float includedAngle = (float)(Math.Atan(1.0 * height / width));//矩形对角线与横边的夹角
                angle = (float)(Math.Atan2(e.Y - leftUpPoint.Y, e.X - leftUpPoint.X));//直线斜率对应的角度 
                rightUpPoint = GetRotatePoint(width, leftUpPoint, angle);
                leftDownPoint = GetRotatePoint(height, leftUpPoint, (float)(angle + Math.PI / 2));
                rightDownPoint = GetRotatePoint((int)(Math.Sqrt(width * width + height * height)), leftUpPoint, angle + includedAngle);
                //计算旋转后左侧边的斜率
                if (leftUpPoint.X != leftDownPoint.X)
                    this.slope = 1.0 * (leftUpPoint.Y - leftDownPoint.Y) / (leftUpPoint.X - leftDownPoint.X);
            }
            else if (selectedIndex == 3)
            {
                if (leftUpPoint.X != leftDownPoint.X)
                {
                    rightUpPoint = GetChangeSizePoint(slope, leftUpPoint, e);
                    leftDownPoint = GetChangeSizePoint(-1 / slope, leftUpPoint, e);
                }
                else
                {
                    rightUpPoint.X = e.X;
                    leftDownPoint.Y = e.Y;
                }
                rightDownPoint = new Point(e.X, e.Y);
                width = (int)(Math.Sqrt(Math.Pow(rightUpPoint.X - leftUpPoint.X, 2) + Math.Pow(rightUpPoint.Y - leftUpPoint.Y, 2)));
                height = (int)(Math.Sqrt(Math.Pow(leftUpPoint.X - leftDownPoint.X, 2) + Math.Pow(leftUpPoint.Y - leftDownPoint.Y, 2)));
            }
            else if (selectedIndex == 4)
            {
                if (leftUpPoint.X != leftDownPoint.X)
                {
                    leftUpPoint = GetChangeSizePoint(-1 / slope, leftDownPoint, e);
                    rightUpPoint = GetChangeSizePoint(-1 / slope, rightDownPoint, e);
                }
                else
                {
                    leftUpPoint.Y = e.Y;
                    rightUpPoint.Y = e.Y;
                }
                height = (int)(Math.Sqrt(Math.Pow(leftUpPoint.X - leftDownPoint.X, 2) + Math.Pow(leftUpPoint.Y - leftDownPoint.Y, 2)));
            }
            else if (selectedIndex == 5)
            {
                if (leftUpPoint.X != leftDownPoint.X)
                {
                    leftUpPoint = GetChangeSizePoint(slope, rightUpPoint, e);
                    leftDownPoint = GetChangeSizePoint(slope, rightDownPoint, e);
                }
                else
                {
                    leftUpPoint.X = e.X;
                    leftDownPoint.X = e.X;
                }
                width = (int)(Math.Sqrt(Math.Pow(rightUpPoint.X - leftUpPoint.X, 2) + Math.Pow(rightUpPoint.Y - leftUpPoint.Y, 2)));
            }
            else if (selectedIndex == 6)
            {
                if (leftUpPoint.X != leftDownPoint.X)
                {
                    leftDownPoint = GetChangeSizePoint(-1 / slope, leftUpPoint, e);
                    rightDownPoint = GetChangeSizePoint(-1 / slope, rightUpPoint, e);
                }
                else
                {
                    leftDownPoint.Y = e.Y;
                    rightDownPoint.Y = e.Y;
                }
                height = (int)(Math.Sqrt(Math.Pow(leftUpPoint.X - leftDownPoint.X, 2) + Math.Pow(leftUpPoint.Y - leftDownPoint.Y, 2)));
            }
            else if (selectedIndex == 7)
            {
                if (leftUpPoint.X != leftDownPoint.X)
                {
                    rightUpPoint = GetChangeSizePoint(slope, leftUpPoint, e);
                    rightDownPoint = GetChangeSizePoint(slope, leftDownPoint, e);
                }
                else
                {
                    rightUpPoint.X = e.X;
                    rightDownPoint.X = e.X;
                }
                width = (int)(Math.Sqrt(Math.Pow(rightUpPoint.X - leftUpPoint.X, 2) + Math.Pow(rightUpPoint.Y - leftUpPoint.Y, 2)));
            }
        }
        protected Point GetChangeSizePoint(double k, Point relativePoint, MouseEventArgs e)
        {
            double x = (relativePoint.Y - e.Y + k * e.X + 1.0 * relativePoint.X / k) * k / (k * k + 1);
            int y = (int)(k * (x - e.X) + e.Y);
            return (new Point((int)x, y));
        }
        protected Point GetRotatePoint(int radius, Point centerPoint, float angle)
        {
            int x = centerPoint.X + (int)(radius * Math.Cos(angle));
            int y = centerPoint.Y + (int)(radius * Math.Sin(angle));
            return (new Point(x, y));
        }
        public override string ToString()
        {
            string printMsg = "[矩形(" + this.leftUpPoint.X + "," + this.leftUpPoint.Y + ")]->[ID:" + this.Id + "]";
            return printMsg;
        }
        public override string GetDrawObjectMsg()
        {
            string drawObjectMsg = "矩形->起始位置(" + this.leftUpPoint.X + "," + this.leftUpPoint.Y + "),宽高(" + this.width + "," + this.height + "),偏移角度:" + ((int)(angle * 180 / Math.PI)) + "°";
            return drawObjectMsg;
        }
        public override Rectangle GetRectangle()
        {
            return new Rectangle(leftUpPoint.X, leftUpPoint.Y, width, height);
        }
        public override Point[] GetPoints()
        {
            return new Point[] { leftUpPoint, rightUpPoint, rightDownPoint, leftDownPoint };
        }
        public override bool IsAllInRectangle(Region region)
        {
            return (region.IsVisible(leftUpPoint) && region.IsVisible(leftDownPoint) && region.IsVisible(rightDownPoint) && region.IsVisible(rightUpPoint));
        }
        public override DrawObject Clone(Point point)
        {
            return new DrawRectangle(point);
        }
        public override Point[] GetTextBoxLocation()
        {
            return new Point[] { leftUpPoint, rightDownPoint };
        }
    }

}
